/////////////////////////////////////////////
// CMARectWindow custom object.

#include "StdAfx.h"
#include "StdArx.h"
#include "dbproxy.h"
#include "geassign.h"
#include "acgi.h"

#define VERSION_CMARECTWINDOW 1


//{{AFX_ARX_MACRO
ACRX_DXF_DEFINE_MEMBERS(CMARectWindow, AcDbEntity,
                        AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent,
                        AcDbProxyEntity::kNoOperation,
                        CMARECTWINDOW, CMACh9_3
);
//}}AFX_ARX_MACRO


// Constructor / Destructor

CMARectWindow::CMARectWindow()
{
	// TODO: do your initialization.

}

CMARectWindow::~CMARectWindow()
{
	// TODO: clean up.

}


Acad::ErrorStatus CMARectWindow::getOsnapPoints(AcDb::OsnapMode osnapMode,
                                                int gsSelectionMark,
                                                const AcGePoint3d& pickPoint,
                                                const AcGePoint3d& lastPoint,
                                                const AcGeMatrix3d& viewXform,
                                                AcGePoint3dArray& snapPoints,
                                                AcDbIntArray& geomIds) const
{
	assertReadEnabled();

	switch(osnapMode)
	{

		case AcDb::kOsModeEnd:
			return osnapEnd(pickPoint, snapPoints);

		case AcDb::kOsModeMid:
			return osnapMid(pickPoint, snapPoints);

		case AcDb::kOsModeCen:
			return osnapCen(pickPoint, snapPoints);

		case AcDb::kOsModeNear:
		case AcDb::kOsModeQuad:
		case AcDb::kOsModeNode:
		case AcDb::kOsModeIns:
		case AcDb::kOsModePerp:
		case AcDb::kOsModeTan:
		default:
			break;
	}

	return AcDbEntity::getOsnapPoints(osnapMode, gsSelectionMark, pickPoint, lastPoint, viewXform, snapPoints, geomIds);
}

Acad::ErrorStatus CMARectWindow::getGripPoints(AcGePoint3dArray& gripPoints,
                                               AcDbIntArray& osnapModes,
                                               AcDbIntArray& geomIds) const
{
	assertReadEnabled();

	AcGePoint3d ll, lr, ur, ul;
	AcGeVector3d vec;
	double len, ht;


	// Get the window length, height and start point
	len = getWindowLength();
	ht	= getWindowHeight();
	ll	= getWindowStartPoint();

	// Calculate the other 3 corner points
	// from ll
	vec.set(len, 0, 0);
	lr = ll + vec;
	vec.set(0, ht, 0);
	ur = lr + vec;
	ul = ll + vec;


	gripPoints.append(ll);
	gripPoints.append(lr);
	gripPoints.append(ur);
	gripPoints.append(ul);
	gripPoints.append(ll + 0.5 * (ur - ll));


	return Acad::eOk;

}

Acad::ErrorStatus CMARectWindow::moveGripPointsAt(const AcDbIntArray& indices,
                                                  const AcGeVector3d& offset)
{
	assertWriteEnabled();

	AcGePoint3d ll, lr, ur, ul, ctrlpt;

	double len, ht;
	AcGeVector3d vec, ctrlvec;	
	assertWriteEnabled();

	// Get the window length, height and start point
	len = getWindowLength();
	ht	= getWindowHeight();
	ll	= getWindowStartPoint();

	ctrlvec.set(10.0, 10.0, 0.0);

	// Calculate the other 3 corner points
	// from ll
	vec.set(len, 0, 0);
	lr = ll + vec;
	vec.set(0, ht, 0);
	ur = lr + vec;
	ul = ll + vec;

	switch(indices[0])
	{
		case 0:
			// Change the start point and length and height of the window
			// lower left grip

			ll += offset;
			ctrlpt = ur - ctrlvec;

			if(ll.x <= ctrlpt.x && ll.y <= ctrlpt.y)
			{
				setWindowStartPoint(ll);
				setWindowLength(ur.x - ll.x);
				setWindowHeight(ur.y - ll.y);
			}

		break;

		case 1:
			// Change the width of the window
			// lower right grip

			lr += offset;
			ctrlpt = ll + ctrlvec;

			if(lr.x >= ctrlpt.x)
			{
				setWindowLength(lr.x - ll.x);
			}

		break;

		case 2:
			// Change the width and height of the window
			// upper right grip

			ur += offset;
			ctrlpt = ll + ctrlvec;

			if(ur.x >= ctrlpt.x && ur.y >= ctrlpt.y)
			{
				setWindowLength(ur.x - ll.x);
				setWindowHeight(ur.y - ll.y);
			}

		break;

		case 3:
			// Change the height of the window
			// upper left grip

			ul += offset;
			ctrlpt = ll + ctrlvec;

			if(ul.y >= ctrlpt.y)
			{
				setWindowHeight(ul.y - ll.y);
			}

		break;

		case 4:
			// Change the window locatin
			// center grip

			ll += offset;
			setWindowStartPoint(ll);

		break;


	}// end switch

	return Acad::eOk;
}

Acad::ErrorStatus CMARectWindow::getStretchPoints(AcGePoint3dArray& stretchPoints) const
{
	assertReadEnabled();

	AcDbIntArray osnapModes;
	AcDbIntArray geomIds;


	//	getStretchPoints == getGripPoints
	//
	return getGripPoints(stretchPoints, osnapModes, geomIds);
}

Acad::ErrorStatus CMARectWindow::moveStretchPointsAt(const AcDbIntArray& indices,
                                                     const AcGeVector3d& offset)
{
	assertWriteEnabled();
	//	moveStretchPointsAt == moveGripPointsAt
	//
	return moveGripPointsAt(indices, offset);
}

void CMARectWindow::list() const
{
	assertReadEnabled();

	AcDbEntity::list();

	acutPrintf("\t\tProgramming AutoCAD 2000 with ObjectARX\n\t\tby Charles Mc Auley\n");
	acutPrintf("\n\t\tCustom Window Entity");
	acutPrintf("\n\t\tWindow type = %s", m_strWindType);
	acutPrintf("\n\t\tWindow start point = (%.2lf, %.2lf)",
				getWindowStartPoint().x,
				getWindowStartPoint().y);
	acutPrintf("\n\t\tRows = %d", getWindowRows());
	acutPrintf("\n\t\tCols = %d", getWindowCols());
	acutPrintf("\n\t\tLength = %.2lf", getWindowLength());
	acutPrintf("\n\t\tHeight = %.2lf", getWindowHeight());

}

Acad::ErrorStatus CMARectWindow::transformBy(const AcGeMatrix3d& xform)
{
	assertWriteEnabled();

	AcGePoint3d ll;

	ll = getWindowStartPoint();

	ll.transformBy(xform);

	setWindowStartPoint(ll);

	return AcDbEntity::transformBy(xform);
}


Adesk::Boolean CMARectWindow::worldDraw(AcGiWorldDraw* mode)
{
	assertReadEnabled();

	AcGePoint3d PlinePts[5];
	AcGePoint3d ll, lr, ur, ul;
	AcGeVector3d vec;
	double len, ht;

	// Get the window length, height and start point
	len = getWindowLength();
	ht	= getWindowHeight();
	ll	= getWindowStartPoint();

	// Calculate the other 3 corner points
	// from ll
	vec.set(len, 0, 0);
	lr = ll + vec;
	vec.set(0, ht, 0);
	ur = lr + vec;
	ul = ll + vec;
	
	PlinePts[0] = ll;
	PlinePts[1] = lr;
	PlinePts[2] = ur;
	PlinePts[3] = ul;
	PlinePts[4] = ll;

	mode->subEntityTraits().setColor(4);
	mode->geometry().polyline(5, PlinePts);

	return AcDbEntity::worldDraw(mode);

}

Acad::ErrorStatus CMARectWindow::dwgInFields(AcDbDwgFiler* pFiler)
{
	assertWriteEnabled();
	Acad::ErrorStatus es;

	char *pstrWindType = NULL;

	// Call dwgInFields from AcDbEntity
	if ((es = AcDbEntity::dwgInFields(pFiler)) != Acad::eOk) {
		return es;
	}

	// Read version number.
	Adesk::UInt16 version;
	pFiler->readItem(&version);
	if (version > VERSION_CMARECTWINDOW)
		return Acad::eMakeMeProxy;

	// Read the data members.
	switch (version)
	{
		case (1):
			pFiler->readString(&pstrWindType);
			strcpy(m_strWindType, pstrWindType);
			pFiler->readItem(&m_ncols);
			pFiler->readItem(&m_nrows);
			pFiler->readItem(&m_drectFrameLen);
			pFiler->readItem(&m_drectFrameHt);
			pFiler->readItem(&m_lowLeftPt);

			if(pstrWindType != NULL)
			{
				delete pstrWindType;
			}

		break;
	}


	return pFiler->filerStatus();
}

Acad::ErrorStatus CMARectWindow::dwgOutFields(AcDbDwgFiler* pFiler) const
{
	assertReadEnabled();
	Acad::ErrorStatus es;

	// Call dwgOutFields from AcDbEntity
	if ((es = AcDbEntity::dwgOutFields(pFiler)) != Acad::eOk) {
		return es;
	}

	// Write version number.
	pFiler->writeItem((Adesk::UInt16) VERSION_CMARECTWINDOW);

	// Write the data members.
	pFiler->writeItem(m_strWindType);
	pFiler->writeItem(getWindowCols());
	pFiler->writeItem(getWindowRows());
	pFiler->writeItem(getWindowLength());
	pFiler->writeItem(getWindowHeight());
	pFiler->writeItem(getWindowStartPoint());

	return pFiler->filerStatus();
}


// User defined
// Get and Set functions

Adesk::Int32 CMARectWindow::getWindowRows() const
{
	return m_nrows;
}

Adesk::Int32 CMARectWindow::getWindowCols() const
{
	return m_ncols;
}

double CMARectWindow::getWindowHeight() const
{
	return m_drectFrameHt;
}

double CMARectWindow::getWindowLength() const
{
	return m_drectFrameLen;
}

AcGePoint3d CMARectWindow::getWindowStartPoint() const
{
	return m_lowLeftPt;
}


void CMARectWindow::setWindowRows(Adesk::Int32 rowQty)
{
	m_nrows = rowQty;
}

void CMARectWindow::setWindowCols(Adesk::Int32 colQty)
{
	m_ncols = colQty;
}

void CMARectWindow::setWindowHeight(double windHeight)
{
	m_drectFrameHt = windHeight;
}

void CMARectWindow::setWindowLength(double windLength)
{
	m_drectFrameLen = windLength;
}


void CMARectWindow::setWindowStartPoint(AcGePoint3d lowLeftPoint)
{
	m_lowLeftPt = lowLeftPoint;
}

// Private user defined Osnap helper functins
Acad::ErrorStatus CMARectWindow::osnapEnd(const AcGePoint3d& pickPoint,
									   AcGePoint3dArray& snapPoints) const
{
	AcGePoint3d ll, lr, ur, ul;
	AcGeVector3d vec;
	double len, ht;

	assertReadEnabled();

	// Get the window length, height and start point
	len = getWindowLength();
	ht	= getWindowHeight();
	ll	= getWindowStartPoint();

	// Calculate the other 3 corner points
	// from ll
	vec.set(len, 0, 0);
	lr = ll + vec;
	vec.set(0, ht, 0);
	ur = lr + vec;
	ul = ll + vec;

	snapPoints.append(ll);
	snapPoints.append(lr);
	snapPoints.append(ur);
	snapPoints.append(ul);

	return Acad::eOk;
}

Acad::ErrorStatus CMARectWindow::osnapMid(const AcGePoint3d& pickPoint,
									   AcGePoint3dArray& snapPoints) const
{
	AcGePoint3d ll, lr, ur, ul, btm_mid, top_mid, left_mid, right_mid;
	AcGeVector3d vec;
	double len, ht;

	assertReadEnabled();

	// Get the window length, height and start point
	len = getWindowLength();
	ht	= getWindowHeight();
	ll	= getWindowStartPoint();

	// Calculate the other 3 corner points
	// from ll
	vec.set(len, 0, 0);
	lr = ll + vec;
	vec.set(0, ht, 0);
	ur = lr + vec;
	ul = ll + vec;

	// Calculate the mid points
	vec.set(0.5 * len, 0, 0);
	btm_mid = ll + vec;
	top_mid = ul + vec;
	vec.set(0, 0.5 * ht, 0);
	left_mid = ll + vec;
	right_mid = lr + vec;

	snapPoints.append(left_mid);
	snapPoints.append(right_mid);
	snapPoints.append(btm_mid);
	snapPoints.append(top_mid);

	return Acad::eOk;
}

Acad::ErrorStatus CMARectWindow::osnapCen(const AcGePoint3d& pickPoint,
									   AcGePoint3dArray& snapPoints) const
{
	AcGePoint3d ll, ur, cen;
	AcGeVector3d vec;
	double len, ht;

	assertReadEnabled();

	// Get the window length, height and start point
	len = getWindowLength();
	ht	= getWindowHeight();
	ll	= getWindowStartPoint();

	// Calculate the other 3 corner points
	// from ll
	vec.set(len, ht, 0);
	ur = ll + vec;

	cen = ll + 0.5 * vec;

	snapPoints.append(cen);

	return Acad::eOk;
}


Acad::ErrorStatus CMARectWindow::subErase(Adesk::Boolean erasing)
{
	AcDbDatabase *pCurDb;

	pCurDb = acdbHostApplicationServices()->workingDatabase();

	assertReadEnabled();

    Acad::ErrorStatus es = AcDbEntity::subErase(erasing);
    if (es != Acad::eOk)
	{
        return es;
	}

	AcDbDictionary *pNOD, *pDict, *preactDict;
	AcDbObjectId reactId;
	AcDbHandle handEnt;
	char strHandle[17];

	getAcDbHandle(handEnt);
	handEnt.getIntoAsciiBuffer(strHandle);

	pCurDb->getNamedObjectsDictionary(pNOD, AcDb::kForRead);

	pNOD->getAt("WINDO_INFO", (AcDbObject*&)pDict, AcDb::kForRead);
	pDict->getAt(strHandle, (AcDbObject*&)preactDict, AcDb::kForRead);

	reactId = preactDict->objectId();

	removePersistentReactor(reactId);

	preactDict->upgradeOpen();
	preactDict->erase();

	pDict->close();
	pNOD->close();

	return Acad::eOk;
}

